#include "WinComponent.h"
#include <iostream>

namespace core {
    namespace component {

        MenuInstance::MenuInstance(HMENU handle) : ComponentInstance(handle){

        }
        MenuInstance::~MenuInstance(){
            if(ComponentInstance<HMENU>::Handle != NULL){
                DestroyMenu(ComponentInstance<HMENU>::Handle);
                ComponentInstance<HMENU>::Handle = NULL;
            }
        }

        MenuItem::MenuItem(ID_T id, LPCTSTR display_name) : 
            id(id), 
            display_name(display_name)
        {
            flags_asItem = MF_STRING;
        }

        ID_T MenuItem::GetId(){
            return id;
        }

        BOOL_T MenuItem::AppendToMenu(HMENU h_menu){
            return AppendMenu(
                h_menu,
                flags_asItem,
                id,
                display_name
            );
        }

        LPCTSTR MenuItem::GetDisplayName(){
            return display_name;
        }

        Menu::Menu(ID_T _id, LPCTSTR name, MenuNode* pnode) : 
            id(_id), 
            display_name(name), 
            pNode(pnode)
        {
            pnode->data = this;
            pnode->key = id;
            flags_asItem = MF_POPUP | MF_STRING;
        }

        MenuInstance Menu::CreateInstance(){
            return MenuInstance(this->CreateMenu());
        }
        BOOL_T Menu::AppendToMenu(HMENU h_menu){
            return AppendMenu(
                h_menu,
                flags_asItem,
                reinterpret_cast<ID_T>(this->CreateMenu()),
                display_name
            );
        }
        HMENU Menu::CreateMenu(){
            HMENU hMenu = ::CreateMenu();
            for(auto child : pNode->children){
                child.second->data->AppendToMenu(hMenu);
            }
            return hMenu;
        }
        ID_T Menu::GetId(){
            return id;
        }
        LPCTSTR Menu::GetDisplayName(){
            return display_name;
        }
        
        PopupMenu::PopupMenu(ID_T id, LPCTSTR name, MenuNode * pNode) : Menu(id, name, pNode){}

        HMENU PopupMenu::CreateMenu(){
            HMENU hMenu = ::CreatePopupMenu();
            for(auto child : pNode->children){
                child.second->data->AppendToMenu(hMenu);
            }
            return hMenu;
        }

        void CreateMenuTree(ID_T id, LPCTSTR display_name, MenuTree** pptree, bool is_popup_menu){
            *pptree = new MenuTree();
            (*pptree)->root = new MenuNode();
            (*pptree)->root->key = id;
            Menu * p_menu;
            if(is_popup_menu){
                p_menu = new PopupMenu(id, display_name, (*pptree)->root);
            }
            else{
                p_menu = new Menu(id, display_name, (*pptree)->root);
            }
            (*pptree)->root->data = static_cast<IMenuItem *>(p_menu);
        }

        void AddChild(IMenuItem* item, MenuNode ** ppNode){
            MenuNode * child_node = new MenuNode(item->GetId(), item, *ppNode);
            (*ppNode)->children[child_node->key] = child_node;
        }

        void AddMenuItem(ID_T id, LPCTSTR display_name, MenuNode ** ppNode){
            MenuNode * child_node = new MenuNode(id, new MenuItem(id, display_name), *ppNode);
            (*ppNode)->children[child_node->key] = child_node;
        }

        void AddSubMenu(ID_T id, LPCTSTR display_name, MenuNode ** ppNode, bool is_popup_menu){
            MenuNode * child_node = new MenuNode(id, nullptr, *ppNode);
            child_node->data = new Menu(id, display_name, child_node);
            (*ppNode)->children[child_node->key] = child_node;
        }
    }
}